package tjava.apt;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;

import com.sun.source.util.Trees;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Name;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class TjavaModifierProcessor extends AbstractProcessor {

	private int tally;
	private Trees trees;
	private TreeMaker make;
	private Name.Table names;
	private List<Element> genElements;

	@Override
	public synchronized void init(final ProcessingEnvironment env) {
		super.init(env);
		genElements = new ArrayList<Element>();
		trees = Trees.instance(env);
		Context context = ((JavacProcessingEnvironment) env).getContext();
		make = TreeMaker.instance(context);
		names = Name.Table.instance(context);
		tally = 0;
	}

	@Override
	public boolean process(final Set<? extends TypeElement> annotations,
			final RoundEnvironment roundEnv) {
		if (!roundEnv.processingOver()) {
			Set<? extends Element> elementsList = roundEnv.getRootElements();
			for (Element each : elementsList) {
				if (each.getKind() == ElementKind.CLASS
						&& each.getSimpleName().toString().contains("Gen")) {
					genElements.add(each);
				}
			}

			for (Element each : elementsList) {
				if (each.getKind() == ElementKind.CLASS) {
					JCTree tree = (JCTree) trees.getTree(each);
					TreeTranslator visitor = new Inliner();
					tree.accept(visitor);
				}

			}
		} else {
			// processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
			// tally + " changes performed.");
		}
		return false;
	}

	private class Inliner extends TreeTranslator {

		@Override
		public void visitIdent(JCIdent tree) {
			String name = tree.getName().toString();

			// TODO: this thing really gotta be smarter
			boolean match = false;
			for (Element e : genElements) {
				if (e.getSimpleName().toString().replace("Gen", "")
						.equals(name)) {
					result = make.Ident(names.fromString(name + "Gen"));
					result.pos = tree.pos;
					tally++;
					match = true;
				}
			}
			if (!match) {
				super.visitIdent(tree);
			}
		}
	}
}